package com.hzjh.base.style.view.loading;

import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.core.ObservableOnSubscribe;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.schedulers.Schedulers;


/**
 * @author Administrator
 */
public class AnimationsContainer2 {
    public static final String TAG = "UiCore_AnimationsContainer2";
    public static final String NONE_RESOURCES_IN_SDCARD = "NoneResources";
    public static String CURRENT_ANI_NAME = "";
    // 单例
    private JobExecutor executor;


    private AnimationsContainer2() {
//        YYLogUtils.i(TAG + "new AnimationsContainer2");
        executor = new JobExecutor();
    }

    private static class Singleton {
        private static final AnimationsContainer2 INSTANCE = new AnimationsContainer2();
    }

    //获取单例
    public static AnimationsContainer2 getInstance() {
        return Singleton.INSTANCE;
    }


    /**
     * 可交互的
     *
     * @param imageView
     * @return progress dialog animation
     */
    public FramesSequenceAnimation createAnimation(Context context, SafeImageView imageView, ArrayList<AnimationResourceModel> models) {
        return new FramesSequenceAnimation(context, imageView, models);
    }


    /**
     * 循环读取帧---循环播放帧
     */
    public class FramesSequenceAnimation {
        private Context context;
        private List<AnimationResourceModel> models = new ArrayList<>();
        /**
         * 当前动画
         */
        private int modelIndex;
        /**
         * 当前帧
         */
        private int frameIndex;
        /**
         * 开始/停止播放用
         */
        private boolean mShouldRun;
        /**
         * 动画是否正在播放，防止重复播放
         */
        private boolean mIsRunning;
        /**
         * 软引用ImageView，以便及时释放掉
         */
        private WeakReference<SafeImageView> viewWeakReference;
        private int mDelayMillis;

        Disposable disposable;
        /**
         * 播放停止监听
         */
        private AnimationListener mAnimationListener;
        public boolean pause;

        private Bitmap imgBitmap;

        private Bitmap mBitmap;
        /**
         * Bitmap管理类，可有效减少Bitmap的OOM问题
         */
        private BitmapFactory.Options mBitmapOptions;


        private boolean shouldSendEnd = true;


        public FramesSequenceAnimation(Context context, SafeImageView imageView, ArrayList<AnimationResourceModel> models) {
            this.context = context;
            this.models.addAll(models);
            modelIndex = 0;
            frameIndex = 0;
            viewWeakReference = new WeakReference<>(imageView);
            mShouldRun = false;
            mIsRunning = false;
            mDelayMillis = 1000 / 30;


            mBitmapOptions = new BitmapFactory.Options();
            //设置Bitmap内存复用
            //解码时返回可变Bitmap
            mBitmapOptions.inMutable = true;
            //缩放比例
            mBitmapOptions.inSampleSize = 1;
            mBitmap = BitmapFactory.decodeStream(getFileDir(getNextImgStr(this.models.get(modelIndex), 0)), null, mBitmapOptions);
            //Bitmap复用内存块，类似对象池，避免不必要的内存分配和回收
            mBitmapOptions.inBitmap = mBitmap;
            if (mBitmap == null) {
                return;
            }
            if (viewWeakReference.get() != null && mBitmap != null && !mBitmap.isRecycled()) {
//                imgBitmap = mBitmap.copy(mBitmap.getConfig(), true);
                viewWeakReference.get().setImageBitmap(imgBitmap);
            }
        }

        public void reset() {
            //Log.e("frameAnim --->", " reset--->");
            stop();
            viewWeakReference.clear();
        }

        public void reInit(ArrayList<AnimationResourceModel> models) {
            this.models.clear();
            this.models.addAll(models);
            modelIndex = 0;
            frameIndex = 0;
            mShouldRun = false;
            mIsRunning = false;
            pause = false;
        }

        private synchronized String getNext() {
            boolean toGetNext = true;
            boolean isAddModelIndex = false;
            if (frameIndex >= models.get(modelIndex).frameCount - 1) {
                //当前动画最后一帧放完
                if (models.get(modelIndex).loopCount > 0) {
                    //当前播放次数还有
                    frameIndex = 0;
                    models.get(modelIndex).loopCount -= 1;
                    if (!models.get(modelIndex).loop) {
                        // 不是一直循环的动画
                        if (mAnimationListener != null) {
                            // 通知当前动画播完或一个循环播完
                            if (shouldSendEnd) {
                                mAnimationListener.end(models.get(modelIndex).id);
                            }
                        }
                    } else {
                        if (models.size() != 1) {
                            mAnimationListener.end(models.get(modelIndex).id);
                        }
                    }
                } else {
                    if (models.get(modelIndex).isStop) {
                        //停在当前帧
                        toGetNext = false;
                        pause = true;
                    } else {
                        frameIndex = 0;
                        if (modelIndex == models.size() - 1) {
                            //当前是最后一个动画
                            toGetNext = false;
                            pause = true;
                        } else {
                            isAddModelIndex = true;
                            modelIndex++;
                        }
                    }

                    if (mAnimationListener != null && !isAddModelIndex) {
                        // 通知当前动画播完或一个循环播完
                        if (shouldSendEnd) {
                            mAnimationListener.end(models.get(modelIndex).id);
                        }
                    }
                }
            } else {
                frameIndex++;
            }
            if (toGetNext) {
                return getNextImgStr(models.get(modelIndex), frameIndex);
            } else {
                //Log.e("frameAnim --->", " toGetNext ---> false");
                mIsRunning = false;
                return null;
            }
        }

        InputStream getFileDir(String fireName) {
            try {
                return context.getAssets().open(fireName);
            } catch (IOException e) {
                //Log.e("frameAnim --->", "getFileDir error--->");
                e.printStackTrace();
                return null;
            }
        }


        String getNextImgStr(AnimationResourceModel model, int frame) {
            frame=frame+26;
            if (frame < 100) {
                return model.dirName + File.separator + model.prefixStr + "000" + frame + ".png";
            } else if (frame < 1000) {
                return model.dirName + File.separator + model.prefixStr + "00" + frame + ".png";
            } else {
                return null;
            }
        }


        /**
         * 播放动画，同步锁防止多线程读帧时，数据安全问题
         */
        public synchronized void start() {
            if (models.size() > 0) {
                CURRENT_ANI_NAME = models.get(0).id;
            }

            //Log.e("frameAnim --->", "1--->");
            mShouldRun = true;
            if (mIsRunning) {
                //Log.e("frameAnim --->", "start fail--->");
                return;
            }
            if (disposable != null && !disposable.isDisposed()) {
                disposable.dispose();
            }
            //Log.e("frameAnim --->", "2--->");
            disposable = Observable.create((ObservableOnSubscribe<String>) emitter -> {
                        SafeImageView view = viewWeakReference.get();
                        if (!mShouldRun || view == null) {
                            mIsRunning = false;
                            return;
                        }
                        String next = getNext();
                        if (null != next) {
                            mIsRunning = true;
                            emitter.onNext(next);
                            emitter.onComplete();
                        }
                    })
                    .subscribeOn(AndroidSchedulers.mainThread())
                    .observeOn(Schedulers.from(executor))
                    .map(next -> {
                        Bitmap b= FrameAnimationCache.getInstance().getBitmapFromCache(next);
                        if(b!=null){
                            return b;
                        }
                        InputStream in = getFileDir(next);
                        if (in != null) {
                            b = BitmapFactory.decodeStream(in, null, mBitmapOptions);
                            //YYLogUtils.i(TAG+"read a bitmap cost " + (System.currentTimeMillis() - start));
                            in.close();
                            b=b.copy(b.getConfig(), true);
                            FrameAnimationCache.getInstance().addBitmapToCache(next, b);
                            return b;
                        } else {
//                            YYLogUtils.e(TAG + "stream is null");
                            return null;
                        }
                    })
                    .observeOn(Schedulers.from(executor))
                    .filter(bitmap -> bitmap != null && !bitmap.isRecycled())
                    .repeatWhen(objectObservable -> objectObservable.delay(mDelayMillis, TimeUnit.MILLISECONDS))
                    .observeOn(AndroidSchedulers.mainThread())
                    .takeUntil(bitmap -> !mShouldRun)
                    .subscribe(next -> {
//                        YYLogUtils.i(TAG + ">>>>>>>>>>>>>>>>>>>  read bitmap  >> " + next);
                        SafeImageView image = viewWeakReference.get();
                        if (image != null) {
//                            imgBitmap = next.copy(next.getConfig(), true);
                            imgBitmap = next;
                            image.setImageBitmap(imgBitmap);
                        }
                    }, Throwable::printStackTrace);
        }

        public void next(String name) {
            if (name.equals(models.get(modelIndex).id)) {
                //重复当前
                frameIndex = 0;
            } else {
                models.get(modelIndex).loopCount = 0;
            }
        }

        /**
         * 停止播放
         */
        public synchronized void stop() {
            realStop();
        }

        public void realStop() {
            mShouldRun = false;
            disposable.dispose();
            //Log.e("frameAnim --->", "realStop--->");
        }

        public boolean isRunning() {
            return mIsRunning;
        }

        public boolean isLast() {
            return modelIndex == models.size() - 1;
        }

        /**
         * 设置停止播放监听
         *
         * @param listener
         */
        public void setOnAnimStopListener(AnimationListener listener) {
            this.mAnimationListener = listener;
        }

        public void end() {
            this.models.get(modelIndex).loopCount = 0;
            this.models.get(modelIndex).isStop = false;
            //移除当前位置到归位动画前的所有动画
            for (int i = modelIndex + 1; i < models.size() - 1; i++) {
                models.remove(i);
            }
            frameIndex = 0;
            modelIndex = models.size() - 1;
            pause = false;
            //Log.e("frameAnim --->", "end--->");
        }

        public void fadeOut() {
            shouldSendEnd = false;
            SafeImageView imageView = viewWeakReference.get();
            if (imageView != null) {
                ObjectAnimator animator = ObjectAnimator.ofFloat(imageView, "alpha", 1.0f, 1.0f);
                animator.setDuration(50);
                animator.addListener(new Animator.AnimatorListener() {
                    @Override
                    public void onAnimationStart(Animator animation) {

                    }

                    @Override
                    public void onAnimationEnd(Animator animation) {
//                        YYLogUtils.i(TAG + "onAnimationEnd() " + models.get(0).id);
                        stop();
                        mAnimationListener.end(models.get(modelIndex).id);
                        shouldSendEnd = true;
                    }

                    @Override
                    public void onAnimationCancel(Animator animation) {

                    }

                    @Override
                    public void onAnimationRepeat(Animator animation) {

                    }
                });
                animator.start();
            } else {
//                YYLogUtils.e(TAG + "image is null");
            }
        }
    }

    /**
     * 停止播放监听
     */
    public interface AnimationListener {
        /**
         * 动画播放完成
         *
         * @param id animation id
         */
        void end(String id);
    }
}